package com.lin;

import com.lin.bean.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

import java.util.Date;

/**
 * <p>1. 被 @SpringBootApplication 注解标记的类, 表示该类是一个 Spring Boot 应用程序入口类 </p>
 * <p>2. 该类的 main 方法, 是 Spring Boot 应用程序入口方法 </p>
 * <p>3. @SpringBootApplication 注解被以下三个注解标记 </p>
 * <p> @SpringBootConfiguration </p>
 * <p> @EnableAutoConfiguration </p>
 * <p> @ComponentScan </p>
 * <p> 也就是说 @SpringBootApplication 是一个复合注解, 同时拥有以上三个注解功能 </p>
 *     <li> 通过查看 @SpringBootConfiguration 源码, 可以看到 @SpringBootConfiguration </li>
 *     <li> 注解是 @Configuration 注解的子集, 也就是说被 @SpringBootConfiguration 标记的类 </li>
 *     <li> 既是程序入口类, 同时还是 一个配置类 -- 可以通过 @Bean 定义Bean 交给容器管理 </li>
 * <p>
 *     4. 关于 @SpringBootConfiguration 注解, 通过查看源码了解到, 该注解被 @Configuration 注解标记,
 *     因此, 说明 springboot 项目的入口类同时也是 一个配置类, 可以通过 @Bean 定义Bean 交给容器管理
 * </p>
 * <p>
 *     5. @EnableAutoConfiguration 注解, 通过查看源码了解到, 该注解被 @Import(AutoConfigurationImportSelector.class) 标记,
 *     因此, 说明 springboot 项目的入口类, 也是自动配置类, 可以通过 @EnableAutoConfiguration 注解开启自动配置功能
 *     也就是说默认情况下, springboot 项目会自动配置很多功能 <br>
 *     自动配置有什么用呢? <br>
 *     		<span> springboot 会去类路径中查找class, 当类路径中有某个类/某些类, 来自动管理bean, 不需要自己手动配置 </span>
 *     	比如: springboot检测到类路径中有 sqlSessionFactory、 sql 的 jar 包, 或 application.properties 文件中配置了数据源...,
 *     	那么 springboot 会将mybatis中相关bean初始化, 并交给容器管理
 *     	<p> 比如 </p>
 *     	<li> sqlSessionFactory </li>
 *     	<li> transactionManager </li>
 * </p>
 * <p>
 *     6. @ComponentScan 注解,  负责主键扫描, 默认扫描当前包及其子包, 默认扫描所有 @Component 注解的类, 并交给容器管理,
 *     入口类会扫描当前类及其子包, 也就是说, 如果 bean 不在入口类包内,那这个 Bean 不会被扫描到 <br>
 *     		<span> 相当于: @ComponentScan(basePackages = {"com.lin"}) <br>
 *     				或是xml方式: &lt;context:component-scan base-package="com.lin" />	</span>
 * </p>
 */
//@EnableConfigurationProperties(User.class)
@ConfigurationPropertiesScan(basePackages = {"com.lin.bean"})
@SpringBootApplication
@ComponentScan(basePackages = {"com.nil"})
public class SpringBootQuickstartApplication {
	// 定义Bean, 在controller中使用
	@Bean
	public Date hello() {
		return new Date();
	}

	// 程序入口
	public static void main(String[] args) {
		/*
		 * SpringApplication 【spring应用程序】
		 * run 【运行】
		 * run方法的第一个参数【SpringBootQuickstartApplication.class】其实就是配置类字节码,
		 * 		对应以前的配置文件, 或注解方式的配置类
		 * run方法的第二个参数【args】就是程序启动参数, 主要用于接收程序启动时传递的命令行参数, 通过命令动态覆盖配置文件
		 * 		如：   java -jar your-app.jar --server.port=8081 --spring.profiles.active=dev
		 * SpringBootQuickstartApplication.class 又被称为源【起源】
		 */
		ConfigurableApplicationContext context = SpringApplication.run(SpringBootQuickstartApplication.class, args);

		/*Object sqlSessionFactory = context.getBean("sqlSessionFactory");
		System.out.println(sqlSessionFactory);

		Object transactionManager = context.getBean("transactionManager");
		System.out.println(transactionManager);*/

		/*String[] beanDefinitionNames = context.getBeanDefinitionNames();
		for (String beanDefinitionName : beanDefinitionNames) {
			if (beanDefinitionName.equals("ha")) {
				System.out.println(beanDefinitionName);
			}
		}*/

		System.out.println(context.getBeanDefinitionNames().length);

		context.close();

	}

}
